`include "defines.v"
`include "inst.v"
module idu(
  input  clk ,
  input  rst_n,
  input  ctrl_idu_flush_i,
  // frontend in 
  input                 fronted_idu_valid_i,
  output                idu_fronted_ready_o,
  input  [31:0]         fronted_idu_instr_i,
  input  [`VADDR_W-1:0] fronted_idu_vaddr_i,
  input                 fronted_idu_pre_i,
  // IDU 输出的寄存器信号
  output                 idu_isu_valid_o ,
  input                  isu_idu_ready_i ,
  output [`FU_W-1:0]     idu_isu_fu_o    ,
  output [`OP_W-1:0]     idu_isu_op_o    ,
  output [4:0]           idu_isu_rs1_o   ,
  output [4:0]           idu_isu_rs2_o   ,
  output [4:0]           idu_isu_rd_o    ,
  output                 idu_isu_rfwen_o ,
  output [1:0]           idu_isu_src1_o  ,
  output [1:0]           idu_isu_src2_o  ,
  output [`XLEN-1:0]     idu_isu_imm_o   ,
  output [`VADDR_W-1:0]  idu_isu_pc_o    ,
  output [31:0]          idu_isu_inst_o  ,
  output                 idu_isu_pre_o   
);
reg  iduValid;
reg  [31:0]         q_instr;
reg  [`VADDR_W-1:0] q_vaddr;
reg                 q_pre;
wire fronted_idu_hs = fronted_idu_valid_i && idu_fronted_ready_o ;
wire idu_isu_hs     = idu_isu_valid_o && isu_idu_ready_i;
assign idu_fronted_ready_o = ~iduValid || idu_isu_hs  ;
assign idu_isu_valid_o = iduValid;

always@(posedge clk or negedge rst_n)
  if(~rst_n)
    iduValid <= 1'b0;
  else if(ctrl_idu_flush_i)
    iduValid <= 1'b0;
  else if(idu_fronted_ready_o)
    iduValid <= fronted_idu_valid_i;

always@(posedge clk)
  if(fronted_idu_hs)begin
    q_vaddr <= fronted_idu_vaddr_i;
    q_instr <= fronted_idu_instr_i;
    q_pre   <= fronted_idu_pre_i;
  end

/* inst sector */
wire [31:0] inst   = q_instr;
wire [ 6:0] opcode = inst[ 6: 0];
wire [ 4:0] rd     = inst[11: 7];
wire [ 2:0] func3  = inst[14:12];
wire [ 4:0] rs1    = inst[19:15];
wire [ 4:0] rs2    = inst[24:20];
wire [11:0] imm    = inst[31:20];
/* imm generate */
wire [`XLEN-1:0] imm_I = {{52{inst[31]}},inst[31:20]};
wire [`XLEN-1:0] imm_S = {{52{inst[31]}},inst[31:25],inst[11:7]};
wire [`XLEN-1:0] imm_B = {{52{inst[31]}},inst[7],inst[30:25],inst[11:8],1'b0};
wire [`XLEN-1:0] imm_U = {{32{inst[31]}},inst[31:12],12'd0};
wire [`XLEN-1:0] imm_J = {{44{inst[31]}},inst[19:12],inst[20],inst[30:21],1'b0};
wire [`XLEN-1:0] imm_R = {{59{inst[31]}},inst[19:15]};
/* singel inst decoder */
reg [16:0] decsignal ;
always@(*)begin
  casez(q_instr)
    //                    v1  immtype3   fu4       op4         r1rf2    r2rf2   wrf1
    `SLL   :decsignal = {`Y , `IMM_X , `FU_ALU , `ALU_SLL  , `SRC_RF , `SRC_RF , `Y };
    `ADD   :decsignal = {`Y , `IMM_X , `FU_ALU , `ALU_ADD  , `SRC_RF , `SRC_RF , `Y };
    `SUB   :decsignal = {`Y , `IMM_X , `FU_ALU , `ALU_SUB  , `SRC_RF , `SRC_RF , `Y };
    `SLT   :decsignal = {`Y , `IMM_X , `FU_ALU , `ALU_SLT  , `SRC_RF , `SRC_RF , `Y };
    `SLTU  :decsignal = {`Y , `IMM_X , `FU_ALU , `ALU_SLTU , `SRC_RF , `SRC_RF , `Y };
    `AND   :decsignal = {`Y , `IMM_X , `FU_ALU , `ALU_AND  , `SRC_RF , `SRC_RF , `Y };
    `OR    :decsignal = {`Y , `IMM_X , `FU_ALU , `ALU_OR   , `SRC_RF , `SRC_RF , `Y };
    `XOR   :decsignal = {`Y , `IMM_X , `FU_ALU , `ALU_XOR  , `SRC_RF , `SRC_RF , `Y };
    `SRA   :decsignal = {`Y , `IMM_X , `FU_ALU , `ALU_SRA  , `SRC_RF , `SRC_RF , `Y };
    `SRL   :decsignal = {`Y , `IMM_X , `FU_ALU , `ALU_SRL  , `SRC_RF , `SRC_RF , `Y };

    `ADDI  :decsignal = {`Y , `IMM_I , `FU_ALU , `ALU_ADD  , `SRC_RF , `SRC_IM , `Y };
    `ANDI  :decsignal = {`Y , `IMM_I , `FU_ALU , `ALU_AND  , `SRC_RF , `SRC_IM , `Y };
    `ORI   :decsignal = {`Y , `IMM_I , `FU_ALU , `ALU_OR   , `SRC_RF , `SRC_IM , `Y };
    `XORI  :decsignal = {`Y , `IMM_I , `FU_ALU , `ALU_XOR  , `SRC_RF , `SRC_IM , `Y };
    `SLTI  :decsignal = {`Y , `IMM_I , `FU_ALU , `ALU_SLT  , `SRC_RF , `SRC_IM , `Y };
    `SLTIU :decsignal = {`Y , `IMM_I , `FU_ALU , `ALU_SLTU , `SRC_RF , `SRC_IM , `Y };
    `SLLI  :decsignal = {`Y , `IMM_I , `FU_ALU , `ALU_SLL  , `SRC_RF , `SRC_IM , `Y };
    `SRAI  :decsignal = {`Y , `IMM_I , `FU_ALU , `ALU_SRA  , `SRC_RF , `SRC_IM , `Y };
    `SRLI  :decsignal = {`Y , `IMM_I , `FU_ALU , `ALU_SRL  , `SRC_RF , `SRC_IM , `Y };

    `ADDIW :decsignal = {`Y , `IMM_I , `FU_ALUW, `ALU_ADD  , `SRC_RF , `SRC_IM , `Y };
    `SLLIW :decsignal = {`Y , `IMM_I , `FU_ALUW, `ALU_SLL  , `SRC_RF , `SRC_IM , `Y };
    `SRLIW :decsignal = {`Y , `IMM_I , `FU_ALUW, `ALU_SRL  , `SRC_RF , `SRC_IM , `Y };
    `SRAIW :decsignal = {`Y , `IMM_I , `FU_ALUW, `ALU_SRA  , `SRC_RF , `SRC_IM , `Y };
    `ADDW  :decsignal = {`Y , `IMM_X , `FU_ALUW, `ALU_ADD  , `SRC_RF , `SRC_RF , `Y };
    `SUBW  :decsignal = {`Y , `IMM_X , `FU_ALUW, `ALU_SUB  , `SRC_RF , `SRC_RF , `Y };
    `SLLW  :decsignal = {`Y , `IMM_X , `FU_ALUW, `ALU_SLL  , `SRC_RF , `SRC_RF , `Y };
    `SRLW  :decsignal = {`Y , `IMM_X , `FU_ALUW, `ALU_SRL  , `SRC_RF , `SRC_RF , `Y };
    `SRAW  :decsignal = {`Y , `IMM_X , `FU_ALUW, `ALU_SRA  , `SRC_RF , `SRC_RF , `Y };

    `JAL   :decsignal = {`Y , `IMM_J , `FU_BRU , `BRU_JAL  , `SRC_PC , `SRC_IM , `Y };
    `JALR  :decsignal = {`Y , `IMM_I , `FU_BRU , `BRU_JALR , `SRC_RF , `SRC_XX , `Y };
    `BEQ   :decsignal = {`Y , `IMM_B , `FU_BRU , `BRU_BEQ  , `SRC_RF , `SRC_RF , `N };
    `BNE   :decsignal = {`Y , `IMM_B , `FU_BRU , `BRU_BNE  , `SRC_RF , `SRC_RF , `N };
    `BGE   :decsignal = {`Y , `IMM_B , `FU_BRU , `BRU_BGE  , `SRC_RF , `SRC_RF , `N };
    `BGEU  :decsignal = {`Y , `IMM_B , `FU_BRU , `BRU_BGEU , `SRC_RF , `SRC_RF , `N };
    `BLT   :decsignal = {`Y , `IMM_B , `FU_BRU , `BRU_BLT  , `SRC_RF , `SRC_RF , `N };
    `BLTU  :decsignal = {`Y , `IMM_B , `FU_BRU , `BRU_BLTU , `SRC_RF , `SRC_RF , `N };
    
    `LB    :decsignal = {`Y , `IMM_I , `FU_LSU , `LSU_RBS  , `SRC_RF , `SRC_IM , `Y };
    `LBU   :decsignal = {`Y , `IMM_I , `FU_LSU , `LSU_RBU  , `SRC_RF , `SRC_IM , `Y };
    `LH    :decsignal = {`Y , `IMM_I , `FU_LSU , `LSU_RHS  , `SRC_RF , `SRC_IM , `Y };
    `LHU   :decsignal = {`Y , `IMM_I , `FU_LSU , `LSU_RHU  , `SRC_RF , `SRC_IM , `Y };
    `LW    :decsignal = {`Y , `IMM_I , `FU_LSU , `LSU_RWS  , `SRC_RF , `SRC_IM , `Y };
    `LWU   :decsignal = {`Y , `IMM_I , `FU_LSU , `LSU_RWU  , `SRC_RF , `SRC_IM , `Y };
    `LD    :decsignal = {`Y , `IMM_I , `FU_LSU , `LSU_RDX  , `SRC_RF , `SRC_IM , `Y };
    `SB    :decsignal = {`Y , `IMM_S , `FU_LSU , `LSU_WBX  , `SRC_RF , `SRC_RF , `N };
    `SH    :decsignal = {`Y , `IMM_S , `FU_LSU , `LSU_WHX  , `SRC_RF , `SRC_RF , `N };
    `SW    :decsignal = {`Y , `IMM_S , `FU_LSU , `LSU_WWX  , `SRC_RF , `SRC_RF , `N };
    `SD    :decsignal = {`Y , `IMM_S , `FU_LSU , `LSU_WDX  , `SRC_RF , `SRC_RF , `N };

    `AUIPC :decsignal = {`Y , `IMM_U , `FU_ALU , `ALU_ADD  , `SRC_PC , `SRC_IM , `Y };
    `LUI   :decsignal = {`Y , `IMM_U , `FU_ALU , `ALU_ADD  , `SRC_XX , `SRC_IM , `Y };

    `CSRRW :decsignal = {`Y , `IMM_X , `FU_CSR , `CSR_W    , `SRC_RF , `SRC_XX , `Y };
    `CSRRS :decsignal = {`Y , `IMM_X , `FU_CSR , `CSR_S    , `SRC_RF , `SRC_XX , `Y };
    `CSRRC :decsignal = {`Y , `IMM_X , `FU_CSR , `CSR_C    , `SRC_RF , `SRC_XX , `Y };
    `CSRRWI:decsignal = {`Y , `IMM_R , `FU_CSR , `CSR_W    , `SRC_XX , `SRC_IM , `Y };
    `CSRRSI:decsignal = {`Y , `IMM_R , `FU_CSR , `CSR_S    , `SRC_XX , `SRC_IM , `Y };
    `CSRRCI:decsignal = {`Y , `IMM_R , `FU_CSR , `CSR_C    , `SRC_XX , `SRC_IM , `Y };

    `ECALL :decsignal = {`Y , `IMM_X , `FU_CSR , `CSR_P    , `SRC_XX , `SRC_XX , `N };
    `MRET  :decsignal = {`Y , `IMM_X , `FU_CSR , `CSR_P    , `SRC_XX , `SRC_XX , `N };

   `FENCE_I:decsignal = {`Y , `IMM_X , `FU_LSU , `LSU_FEI  , `SRC_XX , `SRC_XX , `N }; 

    `TRAP  :decsignal = {`Y , `IMM_X , `FU_ALU , `ALU_ADD  , `SRC_XX , `SRC_XX , `N }; 
    `PUTCH :decsignal = {`Y , `IMM_X , `FU_ALU , `ALU_ADD  , `SRC_XX , `SRC_XX , `N }; 
    
    // `NOP   :decsignal = {`Y , `IMM_X , `FU_ALU , `ALU_ADD  , `SRC_XX , `SRC_XX , `N };
  default:decsignal = {`N , `IMM_X , `FU_XXX , `ALU_XXXX , `N,   `N ,  `N};
  endcase
end
/* control signal generate */
assign {idu_isu_fu_o,
        idu_isu_op_o,
        idu_isu_src1_o,
        idu_isu_src2_o,
        idu_isu_rfwen_o} = decsignal[12:0];

assign idu_isu_rs1_o   = rs1;
assign idu_isu_rs2_o   = rs2;
assign idu_isu_rd_o    = rd ;
assign idu_isu_imm_o   = ({`XLEN{decsignal[15:13] == `IMM_I}} & imm_I) | 
                         ({`XLEN{decsignal[15:13] == `IMM_S}} & imm_S) | 
                         ({`XLEN{decsignal[15:13] == `IMM_B}} & imm_B) | 
                         ({`XLEN{decsignal[15:13] == `IMM_U}} & imm_U) | 
                         ({`XLEN{decsignal[15:13] == `IMM_J}} & imm_J) | 
                         ({`XLEN{decsignal[15:13] == `IMM_R}} & imm_R) |
                         ({`XLEN{decsignal[15:13] == `IMM_X}} & 'd0) ;
assign idu_isu_pc_o    = q_vaddr;
assign idu_isu_inst_o  = q_instr;
assign idu_isu_pre_o   = q_pre  ;
endmodule
